﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;

namespace BlamanticUI.Components;

/// <summary>
/// Represents a default service。
/// </summary>
internal class ToastService : IToastService
{

    private ReaderWriterLockSlim _toastControllerLocker;
    private Dictionary<string, ICollection<ToastController>> _toasts;

    //private Queue<ToastController> _toastsQueue;
    
    /// <summary>
    /// Initializes a new instance of the <see cref="ToastService"/> class.
    /// </summary>
    public ToastService()
    {
        _toasts = new();
        _toastControllerLocker = new();
    }

    public IDictionary<string, ICollection<ToastController>> Toasters
    {
        get
        {
            _toastControllerLocker.EnterReadLock();
            try
            {
                return _toasts;
            }
            finally
            {
                _toastControllerLocker.ExitReadLock();
            }

        }
    }

    public ToastSetting Setting { get; private set; }

    public event Action OnToastUpdating;

    /// <summary>
    /// Shows toast by specified setting action.
    /// </summary>
    /// <param name="setting">The setting action.</param>
    public void Show(ToastSetting setting)
    {

        Setting = setting ?? throw new ArgumentNullException(nameof(setting));

        if (string.IsNullOrEmpty(Setting.Key))
        {
            throw new ArgumentException("The value of Key is required", nameof(Setting.Key));
        }

        Setting.OnSettingChanged += NotifySettingChanged;
        Add(new(Setting));
    }

    public void Add(ToastController toastController)
    {
        if (toastController is null)
        {
            throw new ArgumentNullException(nameof(toastController));
        }

        _toastControllerLocker.EnterWriteLock();
        try
        {
            toastController.OnClosing += Remove;
            if (!_toasts.ContainsKey(Setting.Key))
            {
                _toasts.Add(Setting.Key, new List<ToastController>());
            }

            _toasts[Setting.Key].Add(toastController);
            this.DebugLine(nameof(Add), $"{nameof(toastController.StateStyle.AnimationId)}:{toastController.StateStyle.AnimationId}");
        }
        finally
        {
            _toastControllerLocker.ExitWriteLock();
        }
        NotifyToastChanged();
    }

    public void Clear()
    {
        _toastControllerLocker.EnterWriteLock();
        try
        {
            Clear(_toasts[Setting.Key]);
        }
        finally
        {
            _toastControllerLocker.ExitWriteLock();
        }
        NotifyToastChanged();
    }

    private void Clear(IEnumerable<ToastController> controllers)
    {
        this.DebugLine(nameof(Clear), $"{nameof(_toasts)}还有：{_toasts.Count}个，{nameof(controllers)}:{controllers.Count()}个");
        if (!controllers.Any())
        {
            return;
        }

        foreach (var item in controllers)
        {
            item.OnClosing -= Remove;
            item.Dispose();
        }
        _toasts.Clear();
    }

    public void Remove(ToastController conrtoller)
    {
        conrtoller.Dispose();
        conrtoller.OnClosing -= Remove;

        _toastControllerLocker.EnterWriteLock();
        try
        {
            this.DebugLine(nameof(Remove),$"Before Remove，{nameof(_toasts)}:{_toasts.Count()}个");
            var removed = _toasts[Setting.Key].Remove(conrtoller);
            this.DebugLine(nameof(Remove), $"成功移除：{removed}");
            this.DebugLine(nameof(Remove), $"After Remove，{nameof(_toasts)}:{_toasts.Count()}个");
            this.DebugLine(nameof(Remove), $"{nameof(conrtoller.StateStyle.AnimationId)}：{conrtoller.StateStyle.AnimationId}");
        }
        finally
        {
            _toastControllerLocker.ExitWriteLock();
        }

        NotifyToastChanged();
    }

    void NotifySettingChanged() => OnToastUpdating?.Invoke();

    void NotifyToastChanged() => OnToastUpdating?.Invoke();

    public void Dispose()
    {
        this.DebugLine(nameof(Dispose), $"{nameof(_toasts)}:{_toasts.Count()}个");
        if (Setting is not null)
        {
            Setting.OnSettingChanged -= NotifySettingChanged;
        }
        Clear(_toasts[Setting.Key]);
    }
}
